package org.osgroup.project;

import org.osgroup.visitor.BaseVisitor;

import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 激流勇进项目 - 使用银行家算法管理设备资源
 */
public class RollerCoaster extends BaseProject {
    
    // 设备类型枚举
    public enum EquipmentType {
        WATER_GUN("水枪", 0),
        RAINCOAT("雨衣", 1),
        WATERPROOF_BAG("手机防水袋", 2);
        
        private final String name;
        private final int index;
        
        EquipmentType(String name, int index) {
            this.name = name;
            this.index = index;
        }
        
        public String getName() { return name; }
        public int getIndex() { return index; }
    }
    
    // 银行家算法相关
    private static final int RESOURCE_TYPES = 3; // 资源种类数
    private int[] available;      // 可用资源向量
    private int[] total;          // 总资源向量
    private Map<String, int[]> allocation;  // 已分配资源矩阵 (游客ID -> 已分配资源)
    private Map<String, int[]> maxDemand;   // 最大需求矩阵 (游客ID -> 最大需求)
    private Map<String, int[]> need;        // 需求矩阵 (游客ID -> 还需要的资源)
    
    private final Lock bankerLock = new ReentrantLock();
    
    // 排队信息
    private final Queue<BaseVisitor> waitQueue = new LinkedList<>();
    private final Lock queueLock = new ReentrantLock();
    private int estimatedWaitTime = 30; // 预计等待时间(分钟)
    
    // 项目状态
    private String projectStatus = "running"; // running, maintenance, closed, error
    
    /**
     * 构造函数
     * @param projectId 项目ID
     * @param projectName 项目名称
     * @param waterGunCount 水枪总数
     * @param raincoatCount 雨衣总数
     * @param waterproofBagCount 防水袋总数
     */
    public RollerCoaster(String projectId, String projectName, 
                        int waterGunCount, int raincoatCount, int waterproofBagCount) {
        super();
        this.setProjectName(projectName);
        
        // 初始化资源向量
        this.total = new int[]{waterGunCount, raincoatCount, waterproofBagCount};
        this.available = new int[]{waterGunCount, raincoatCount, waterproofBagCount};
        this.allocation = new HashMap<>();
        this.maxDemand = new HashMap<>();
        this.need = new HashMap<>();
        
        System.out.println("✅ 激流勇进项目已创建: " + projectName);
        System.out.println("   水枪: " + waterGunCount + " 个");
        System.out.println("   雨衣: " + raincoatCount + " 件");
        System.out.println("   防水袋: " + waterproofBagCount + " 个");
    }
    
    /**
     * 游客请求设备资源
     * @param visitor 游客
     * @param request 请求的资源数量 [水枪, 雨衣, 防水袋]
     * @return 是否分配成功
     */
    public boolean requestEquipment(BaseVisitor visitor, int[] request) {
        bankerLock.lock();
        try {
            String visitorId = visitor.getName();
            
            // 如果是新游客,设置最大需求
            if (!maxDemand.containsKey(visitorId)) {
                maxDemand.put(visitorId, request.clone());
                allocation.put(visitorId, new int[RESOURCE_TYPES]);
                need.put(visitorId, request.clone());
            } else {
                // 🔧 已有预约的用户再次预约,累加最大需求和需求
                int[] currentMaxDemand = maxDemand.get(visitorId);
                int[] currentNeed = need.get(visitorId);
                for (int i = 0; i < RESOURCE_TYPES; i++) {
                    currentMaxDemand[i] += request[i];
                    currentNeed[i] += request[i];
                }
                System.out.println("📝 [" + visitorId + "] 累加需求: " + 
                                 "水枪×" + request[0] + ", 雨衣×" + request[1] + 
                                 ", 防水袋×" + request[2]);
            }
            
            // 检查请求是否超过需求
            int[] currentNeed = need.get(visitorId);
            for (int i = 0; i < RESOURCE_TYPES; i++) {
                if (request[i] > currentNeed[i]) {
                    System.out.println("❌ [" + visitorId + "] 请求资源超过最大需求");
                    return false;
                }
            }
            
            // 检查请求是否超过可用资源
            for (int i = 0; i < RESOURCE_TYPES; i++) {
                if (request[i] > available[i]) {
                    System.out.println("⏳ [" + visitorId + "] 资源不足,加入等待队列");
                    addToWaitQueue(visitor);
                    return false;
                }
            }
            
            // 尝试分配(安全性检查)
            if (isSafeState(visitorId, request)) {
                // 分配资源
                allocateResources(visitorId, request);
                System.out.println("✅ [" + visitorId + "] 成功获取设备: " + 
                                 "水枪×" + request[0] + ", 雨衣×" + request[1] + 
                                 ", 防水袋×" + request[2]);
                return true;
            } else {
                System.out.println("⚠️ [" + visitorId + "] 分配会导致不安全状态,加入等待队列");
                addToWaitQueue(visitor);
                return false;
            }
            
        } finally {
            bankerLock.unlock();
        }
    }
    
    /**
     * 游客归还设备资源
     * @param visitor 游客
     * @param release 归还的资源数量 [水枪, 雨衣, 防水袋]
     */
    public void releaseEquipment(BaseVisitor visitor, int[] release) {
        bankerLock.lock();
        try {
            String visitorId = visitor.getName();
            
            if (!allocation.containsKey(visitorId)) {
                System.out.println("⚠️ [" + visitorId + "] 没有分配记录");
                return;
            }
            
            int[] currentAllocation = allocation.get(visitorId);
            
            // 检查归还数量是否合法
            for (int i = 0; i < RESOURCE_TYPES; i++) {
                if (release[i] > currentAllocation[i]) {
                    System.out.println("❌ [" + visitorId + "] 归还资源超过已分配数量");
                    return;
                }
            }
            
            // 释放资源
            for (int i = 0; i < RESOURCE_TYPES; i++) {
                available[i] += release[i];
                currentAllocation[i] -= release[i];
                need.get(visitorId)[i] += release[i];
            }
            
            System.out.println("✅ [" + visitorId + "] 归还设备: " + 
                             "水枪×" + release[0] + ", 雨衣×" + release[1] + 
                             ", 防水袋×" + release[2]);
            
            // 如果该游客已归还所有资源,清除记录
            boolean allReleased = true;
            for (int i = 0; i < RESOURCE_TYPES; i++) {
                if (currentAllocation[i] > 0) {
                    allReleased = false;
                    break;
                }
            }
            if (allReleased) {
                allocation.remove(visitorId);
                maxDemand.remove(visitorId);
                need.remove(visitorId);
            }
            
            // 尝试处理等待队列
            processWaitQueue();
            
        } finally {
            bankerLock.unlock();
        }
    }
    
    /**
     * 银行家算法 - 安全性检查
     */
    private boolean isSafeState(String visitorId, int[] request) {
        // 临时分配资源
        int[] work = available.clone();
        Map<String, Boolean> finish = new HashMap<>();
        
        for (int i = 0; i < RESOURCE_TYPES; i++) {
            work[i] -= request[i];
        }
        
        // 初始化finish
        for (String vid : allocation.keySet()) {
            finish.put(vid, false);
        }
        
        // 查找安全序列
        List<String> safeSequence = new ArrayList<>();
        int count = 0;
        
        while (count < allocation.size()) {
            boolean found = false;
            
            for (String vid : allocation.keySet()) {
                if (finish.get(vid)) continue;
                
                int[] currentNeed = need.get(vid);
                // 临时更新需求(如果是当前请求的游客)
                if (vid.equals(visitorId)) {
                    currentNeed = currentNeed.clone();
                    for (int i = 0; i < RESOURCE_TYPES; i++) {
                        currentNeed[i] -= request[i];
                    }
                }
                
                // 检查是否可以满足需求
                boolean canFinish = true;
                for (int i = 0; i < RESOURCE_TYPES; i++) {
                    if (currentNeed[i] > work[i]) {
                        canFinish = false;
                        break;
                    }
                }
                
                if (canFinish) {
                    // 回收资源
                    int[] alloc = allocation.get(vid);
                    if (vid.equals(visitorId)) {
                        for (int i = 0; i < RESOURCE_TYPES; i++) {
                            work[i] += alloc[i] + request[i];
                        }
                    } else {
                        for (int i = 0; i < RESOURCE_TYPES; i++) {
                            work[i] += alloc[i];
                        }
                    }
                    
                    finish.put(vid, true);
                    safeSequence.add(vid);
                    count++;
                    found = true;
                    break;
                }
            }
            
            if (!found) {
                // 找不到可以完成的进程,不安全
                return false;
            }
        }
        
        System.out.println("🔒 安全序列: " + String.join(" -> ", safeSequence));
        return true;
    }
    
    /**
     * 分配资源
     */
    private void allocateResources(String visitorId, int[] request) {
        int[] alloc = allocation.get(visitorId);
        int[] currentNeed = need.get(visitorId);
        
        for (int i = 0; i < RESOURCE_TYPES; i++) {
            available[i] -= request[i];
            alloc[i] += request[i];
            currentNeed[i] -= request[i];
        }
    }
    
    /**
     * 加入等待队列
     */
    private void addToWaitQueue(BaseVisitor visitor) {
        queueLock.lock();
        try {
            if (!waitQueue.contains(visitor)) {
                waitQueue.offer(visitor);
                estimatedWaitTime = waitQueue.size() * 5; // 每人预计5分钟
            }
        } finally {
            queueLock.unlock();
        }
    }
    
    /**
     * 处理等待队列
     */
    private void processWaitQueue() {
        queueLock.lock();
        try {
            if (waitQueue.isEmpty()) return;
            
            System.out.println("📋 正在处理等待队列,当前等待人数: " + waitQueue.size());
            // 这里可以尝试为等待队列中的游客分配资源
            // 简化实现:通知队列已更新
            
        } finally {
            queueLock.unlock();
        }
    }
    
    // ==================== Getter方法 ====================
    
    public int[] getAvailable() {
        return available.clone();
    }
    
    public int[] getTotal() {
        return total.clone();
    }
    
    public int getQueueCount() {
        queueLock.lock();
        try {
            return waitQueue.size();
        } finally {
            queueLock.unlock();
        }
    }
    
    public int getEstimatedWaitTime() {
        queueLock.lock();
        try {
            return estimatedWaitTime;
        } finally {
            queueLock.unlock();
        }
    }
    
    public String getProjectStatus() {
        return projectStatus;
    }
    
    public void setProjectStatus(String status) {
        this.projectStatus = status;
    }
    
    /**
     * 获取设备状态
     */
    public Map<String, Object> getEquipmentStatus() {
        bankerLock.lock();
        try {
            Map<String, Object> status = new HashMap<>();
            
            for (EquipmentType type : EquipmentType.values()) {
                int idx = type.getIndex();
                Map<String, Object> equipInfo = new HashMap<>();
                equipInfo.put("available", available[idx]);  // 修改为 "available"
                equipInfo.put("total", total[idx]);
                
                // 计算状态
                double ratio = (double) available[idx] / total[idx];
                if (ratio >= 0.5) {
                    equipInfo.put("status", "available");
                } else if (ratio > 0) {
                    equipInfo.put("status", "in_use");
                } else {
                    equipInfo.put("status", "maintenance");
                }
                
                status.put(getEquipmentKey(type), equipInfo);
            }
            
            return status;
        } finally {
            bankerLock.unlock();
        }
    }
    
    private String getEquipmentKey(EquipmentType type) {
        switch (type) {
            case WATER_GUN: return "waterGun";
            case RAINCOAT: return "raincoat";
            case WATERPROOF_BAG: return "phoneBag";  // 前端使用 phoneBag
            default: return type.name().toLowerCase();
        }
    }
    
    @Override
    public void sendHeartbeat() {
        super.sendHeartbeat();
        // 添加空指针检查,因为父类构造函数会调用此方法,此时available可能还未初始化
        if (available != null && total != null) {
            System.out.println("💓 [激流勇进] 设备状态 - 水枪:" + available[0] + "/" + total[0] + 
                             ", 雨衣:" + available[1] + "/" + total[1] + 
                             ", 防水袋:" + available[2] + "/" + total[2]);
        }
    }
}
